import CryptoJS from "crypto-js"
import dayjs from "dayjs"
import "dayjs/locale/zh-cn"
dayjs.locale("zh-cn")

// 全局参数存储
let params = {}

// 请求相关存储
let request = {
    headers: {},
    query: {},
    body: null,
}

// 参数操作
const getParam = (key) => {
    return params[key]
}

const setParam = (key, value) => {
    params[key] = value
}

const getAllParams = () => {
    return params
}

// 请求相关操作
const getRequest = () => {
    return request
}

const setRequestHeaders = (key, value) => {
    request.headers[key] = value
}

const getRequestHeaders = (key) => {
    return request.headers[key]
}

const setRequestQuery = (key, value) => {
    request.query[key] = value
}

const getRequestQuery = (key) => {
    return request.query[key]
}

const setRequestBody = (value) => {
    request.body = value
}

const getRequestBody = () => {
    return request.body
}

// AES 加解密
const aes = {
    encryptECB(message, key, keySize = 128) {
        // 根据密钥长度补全或截断密钥
        const keyBytes = keySize / 8
        const paddedKey = key.padEnd(keyBytes, "\0").slice(0, keyBytes)
        const keyWordArray = CryptoJS.enc.Utf8.parse(paddedKey)
        return CryptoJS.AES.encrypt(message, keyWordArray, {
            mode: CryptoJS.mode.ECB,
            padding: CryptoJS.pad.Pkcs7,
            keySize: keySize / 32,
        }).toString()
    },
    decryptECB(ciphertext, key, keySize = 128) {
        const keyBytes = keySize / 8
        const paddedKey = key.padEnd(keyBytes, "\0").slice(0, keyBytes)
        const keyWordArray = CryptoJS.enc.Utf8.parse(paddedKey)
        return CryptoJS.AES.decrypt(ciphertext, keyWordArray, {
            mode: CryptoJS.mode.ECB,
            padding: CryptoJS.pad.Pkcs7,
            keySize: keySize / 32,
        }).toString(CryptoJS.enc.Utf8)
    },
    encryptCBC(message, key, iv, keySize = 128) {
        const keyBytes = keySize / 8
        const paddedKey = key.padEnd(keyBytes, "\0").slice(0, keyBytes)
        const keyWordArray = CryptoJS.enc.Utf8.parse(paddedKey)
        const ivWordArray = CryptoJS.enc.Utf8.parse(iv)
        return CryptoJS.AES.encrypt(message, keyWordArray, {
            iv: ivWordArray,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7,
            keySize: keySize / 32,
        }).toString()
    },
    decryptCBC(ciphertext, key, iv, keySize = 128) {
        const keyBytes = keySize / 8
        const paddedKey = key.padEnd(keyBytes, "\0").slice(0, keyBytes)
        const keyWordArray = CryptoJS.enc.Utf8.parse(paddedKey)
        const ivWordArray = CryptoJS.enc.Utf8.parse(iv)
        return CryptoJS.AES.decrypt(ciphertext, keyWordArray, {
            iv: ivWordArray,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7,
            keySize: keySize / 32,
        }).toString(CryptoJS.enc.Utf8)
    },
}

// 哈希函数
const hash = {
    md5: (string) => CryptoJS.MD5(string).toString(),
    sha1: (string) => CryptoJS.SHA1(string).toString(),
    sha256: (string) => CryptoJS.SHA256(string).toString(),
}

// Base64
const base64 = {
    encode: (str) => CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(str)),
    decode: (str) => CryptoJS.enc.Base64.parse(str).toString(CryptoJS.enc.Utf8),
}

// URL编码
const url = {
    encode: encodeURIComponent,
    decode: (str) => {
        try {
            const parsed = CryptoJS.enc.Base64.parse(str)
            const result = parsed.toString(CryptoJS.enc.Utf8)
            if (!result) {
                throw new Error("解码结果为空")
            }
            return result
        } catch (error) {
            throw new Error("Base64解码失败: " + (error.message || "无效的Base64字符串"))
        }
    },
}
// 时间处理工具
const time = {
    // 获取当前时间戳(毫秒)
    now: () => {
        return dayjs().valueOf()
    },

    // 获取当前时间戳(秒)
    nowInSeconds: () => {
        return Math.floor(dayjs().valueOf() / 1000)
    },

    // 获取当前时间格式化字符串
    format: (format = "YYYY-MM-DD HH:mm:ss") => {
        return dayjs().format(format)
    },
    // 当前时间加减秒，返回格式化时间
    addSeconds: (seconds, format = "YYYY-MM-DD HH:mm:ss") => {
        return dayjs().add(seconds, "second").format(format)
    },

    // 当前时间加减秒，返回时间戳
    addSecondsTimestamp: (seconds) => {
        return dayjs().add(seconds, "second").valueOf()
    },

    // 指定时间加减秒，返回格式化时间
    addSecondsToDate: (date, seconds, format = "YYYY-MM-DD HH:mm:ss") => {
        return dayjs(date).add(seconds, "second").format(format)
    },

    // 指定时间加减秒，返回时间戳
    addSecondsToDateTimestamp: (date, seconds) => {
        return dayjs(date).add(seconds, "second").valueOf()
    },
}
const random = {
    // 生成UUID v4
    uuid: () => {
        return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
            const r = (Math.random() * 16) | 0
            const v = c === "x" ? r : (r & 0x3) | 0x8
            return v.toString(16)
        })
    },

    // 生成指定范围的随机整数 [min, max]
    int: (min, max) => {
        min = Math.ceil(min)
        max = Math.floor(max)
        return Math.floor(Math.random() * (max - min + 1)) + min
    },

    // 生成指定范围的随机浮点数 [min, max)
    float: (min, max, decimals = 2) => {
        const num = Math.random() * (max - min) + min
        return Number(num.toFixed(decimals))
    },

    // 从数组中随机选择一个元素
    pick: (array) => {
        if (!Array.isArray(array) || array.length === 0) {
            throw new Error("输入必须是非空数组")
        }
        return array[Math.floor(Math.random() * array.length)]
    },

    // 生成指定长度的随机字符串
    string: (length = 8, charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") => {
        let result = ""
        const charsetLength = charset.length
        for (let i = 0; i < length; i++) {
            result += charset.charAt(Math.floor(Math.random() * charsetLength))
        }
        return result
    },
}

// 控制台重写
const consoleTypes = ["log", "error", "warn", "info", "debug"]
consoleTypes.forEach((type) => {
    const original = console[type]
    console[type] = (...args) => {
        try {
            const serializedArgs = args.map((arg) => {
                if (arg === undefined) return "undefined"
                if (arg === null) return "null"
                if (arg instanceof Error) {
                    return `${arg.name}: ${arg.message}`
                }
                if (typeof arg === "object") {
                    try {
                        return JSON.stringify(
                            arg,
                            (key, value) => {
                                if (typeof value === "function") return "[Function]"
                                if (value instanceof Error) return `${value.name}: ${value.message}`
                                if (value instanceof RegExp) return value.toString()
                                if (value instanceof Date) return value.toISOString()
                                if (typeof value === "symbol") return value.toString()
                                if (value === undefined) return "undefined"
                                if (value === null) return "null"
                                return value
                            },
                            2,
                        )
                    } catch (e) {
                        return `[${typeof arg}]`
                    }
                }
                return String(arg)
            })

            const output = {
                type,
                args: serializedArgs,
                timestamp: dayjs().format("YYYY-MM-DD HH:mm:ss"),
            }

            postMessage({ type: "console", output })
        } catch (error) {
            // 如果序列化失败，发送一个简单的错误消息
            postMessage({
                type: "console",
                output: {
                    type: "error",
                    args: ["Failed to serialize console output"],
                    timestamp: dayjs().format("YYYY-MM-DD HH:mm:ss"),
                },
            })
        }
        // 保持原始控制台输出
        original.apply(console, args)
    }
})

// 错误处理
const createErrorObject = (error, type = null) => {
    // 确保返回的对象只包含可序列化的数据
    return {
        message: error.message || String(error),
        type: type || (error.constructor ? error.constructor.name : "UnknownError"),
        location:
            error.lineNumber && error.columnNumber ? `第${error.lineNumber}行, 第${error.columnNumber}列` : undefined,
    }
}

self.onerror = (msg, url, lineNo, columnNo, error) => {
    postMessage({
        type: "error",
        error: createErrorObject(error || new Error(msg)),
        params: JSON.parse(JSON.stringify(getAllParams())),
    })
    return false
}

self.onunhandledrejection = (event) => {
    postMessage({
        type: "error",
        error: createErrorObject(event.reason, "UnhandledPromiseRejectionError"),
        params: JSON.parse(JSON.stringify(getAllParams())),
    })
}

// 执行代码
self.onmessage = async ({ data: { code, initParams } }) => {
    // 初始化参数
    params = { ...initParams }
    console.log("初始化参数:", initParams)
    try {
        // 包装执行代码到异步函数中以捕获异步错误
        const wrappedCode = `
            return (async () => {
                try {
                    ${code}
                } catch (error) {
                    // 处理语法错误
                    if(error instanceof SyntaxError) {
                        console.error('语法错误:', error.message);
                        return {
                            error: error.message,
                            type: 'SyntaxError'
                        };
                    }
                         // 处理 CryptoJS 相关错误
                    if(error.message.includes('Malformed UTF-8 data')) {
                        console.error('数据格式错误: 输入数据包含无效的UTF-8字符');
                        return {
                            error: '数据格式错误: 输入数据包含无效的UTF-8字符',
                            type: 'CryptoError'
                        };
                    }
                    
                    
                    // 处理其他运行时错误
                    const errorInfo = error.stack?.split('\\n')[1] || '';
                    const match = errorInfo.match(/<anonymous>:(\\d+):(\\d+)/);
                    const lineNo = match ? match[1] : '未知';
                    const colNo = match ? match[2] : '未知';
                    
                    console.error('执行错误:', error.message);
                    console.error('错误位置: 第' + lineNo + '行, 第' + colNo + '列');
                    
                    return { 
                        error: error.message,
                        type: error.name,
                        location: '第'+lineNo+'行, 第'+colNo+'列'
                    };
                }
            })();
        `
        const executeCode = new Function(
            "getParam",
            "setParam",
            "getAllParams",
            "getRequest",
            "setRequestHeaders",
            "getRequestHeaders",
            "setRequestQuery",
            "getRequestQuery",
            "setRequestBody",
            "getRequestBody",
            "dayjs",
            "aes",
            "hash",
            "base64",
            "url",
            "time",
            "random",
            wrappedCode,
        )
        const result = executeCode(
            getParam,
            setParam,
            getAllParams,
            getRequest,
            setRequestHeaders,
            getRequestHeaders,
            setRequestQuery,
            getRequestQuery,
            setRequestBody,
            getRequestBody,
            dayjs,
            aes,
            hash,
            base64,
            url,
            time,
            random,
        )
        // 等待异步执行结果
        const executionResult = await result
        // 检查执行结果
        if (executionResult && executionResult.error) {
            postMessage({
                type: "complete",
                status: "error",
                error: {
                    message: executionResult.error,
                    type: executionResult.type || "ExecutionError",
                    location: executionResult.location,
                },
                params: JSON.parse(JSON.stringify(getAllParams())),
            })
        } else {
            postMessage({
                type: "complete",
                status: "success",
                params: JSON.parse(JSON.stringify(getAllParams())),
            })
        }
    } catch (error) {
        console.error("js执行错误:", error.message)
        postMessage({
            type: "complete",
            status: "error",
            error: createErrorObject(error),
            params: JSON.parse(JSON.stringify(getAllParams())),
        })
    }
}
